/**
 *  EKology - An Ecosystem Simulation Framework
 *  Copyright (C) 2008  Aarón Tavío - aaron.tavio at gmail.com - ULPGC
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

package net.ekology.core.gui;

import net.ekology.ekosystem.*;
import net.ekology.core.gui.datatypes.*;

import java.util.Enumeration;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.io.Serializable;


/**
 * @author Aarón Tavío - aaron.tavio at gmail.com
 * @version 1.0.0 - 20081019-1700
 */
public class EKosystemTree extends JTree implements Serializable {
    private static final long serialVersionUID = -7575296075713843325L;

    public EKosystemTree() {
        super();
        reset();
    }
    
    public void addAgent(Agent oAgent) {
        DefaultMutableTreeNode oSelectedNode;
        DefaultMutableTreeNode oChildNode;
        TreePath oSelectedNodePath;
        
        oSelectedNode = this.getSelectedNode();

        oChildNode = new DefaultMutableTreeNode(oAgent);
        oSelectedNode.add(oChildNode);

        oSelectedNodePath = new TreePath(oSelectedNode.getPath());
        if (!this.isExpanded(oSelectedNodePath)) this.expandPath(oSelectedNodePath);
        this.updateUI();
    }
    
    
    public void removeAgent(Agent oAgent) {
        DefaultMutableTreeNode oSelectedNode;
        DefaultMutableTreeNode oParentNode;
        
        oSelectedNode = this.getSelectedNode();
        oParentNode = (DefaultMutableTreeNode) oSelectedNode.getParent();
        this.setSelectionPath(new TreePath(oParentNode.getPath()));
        oSelectedNode.removeFromParent();
        this.updateUI();
    }
    
    
    public void loadModel(EKosystemModel oEKModel) {
        DefaultMutableTreeNode oTreeRoot;
        TreePath oRootPath;
        
        reset();
        oTreeRoot = getRootNode();
        oRootPath = new TreePath(oTreeRoot.getPath());
        // Filling the tree with an instance of the biotope in the root and Classes of the species as children
        try {
            oTreeRoot.setUserObject(oEKModel.getModelBiotope());

            for(Class oClass: oEKModel.getModelAgentClasses()) {
                oTreeRoot.add(new DefaultMutableTreeNode(new Argument<Class>(oClass.getSimpleName(),oClass)));
            }              

            expandPath(oRootPath);
            setSelectionPath(oRootPath);
            updateUI();
        } catch(Exception e) {e.printStackTrace();}
    }
    
    
    public DefaultMutableTreeNode getSelectedNode() {
        return (DefaultMutableTreeNode) this.getLastSelectedPathComponent();
    }
    
    
    public void selectAgent(Agent oAgent) {
        TreePath oPath;
        
        oPath = searchObject(oAgent,getRootNode());
        if (oPath != null) this.setSelectionPath(oPath);
    }
    
    
    private TreePath searchObject(Object oObj, DefaultMutableTreeNode oRoot) {
        TreePath oResult;
        DefaultMutableTreeNode oChildNode;
        Enumeration<DefaultMutableTreeNode> oChildren;
        DefaultMutableTreeNode oChild;
        
        oResult = null;
        if (oRoot.getUserObject().equals(oObj)) oResult = new TreePath(oRoot.getPath());
        else if (oRoot.getChildCount() > 0) {
            oChildren = oRoot.children();
            while (oChildren.hasMoreElements() && oResult == null) {
                oChild = oChildren.nextElement();
                oResult = searchObject(oObj,oChild);
            }
        }
            
        return oResult;
    }
    
    
    public DefaultMutableTreeNode getRootNode() {
        return (DefaultMutableTreeNode) this.getPathForRow(0).getLastPathComponent();
    }
    
    
    public Agent getSelectedAgent() {
        return (getSelectedNode().getUserObject() instanceof Agent)? (Agent) getSelectedNode().getUserObject() : null ;
    }
    
    public void updateAgents(Agent[] aAgent) {
        DefaultMutableTreeNode oAgentNode;
        DefaultMutableTreeNode oSpeciesNode;
        Class oSpecies;
        Enumeration<DefaultMutableTreeNode> oSpeciesNodes;
        Enumeration<DefaultMutableTreeNode> oAgentNodes;
        
        oSpeciesNodes = this.getRootNode().children();
        while(oSpeciesNodes.hasMoreElements()) {
            oSpeciesNode = oSpeciesNodes.nextElement();
            oSpeciesNode.removeAllChildren();
            for(Agent oAgent: aAgent) {
                oSpecies = (Class) Argument.class.cast(oSpeciesNode.getUserObject()).getValue();
                if (oSpecies.isInstance(oAgent)) oSpeciesNode.add(new DefaultMutableTreeNode(oAgent));
            }

        }
        
        updateUI();
    }
    
    public void reset() {
        DefaultMutableTreeNode oRoot;
        
        oRoot = getRootNode();
        oRoot.removeAllChildren();
        oRoot.setUserObject("(Empty)");
        
        updateUI();
    }

}
